package com.zhangmeng.tools.controller;

import com.zhangmeng.tools.utils.AlertUtils;
import com.zhangmeng.tools.utils.ImagePath;
import javafx.application.Platform;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.concurrent.Task;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.control.ProgressBar;
import javafx.scene.control.TextField;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.StackPane;
import javafx.scene.media.Media;
import javafx.scene.media.MediaPlayer;
import javafx.scene.media.MediaView;
import javafx.stage.DirectoryChooser;
import javafx.stage.FileChooser;
import javafx.stage.Stage;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FilenameUtils;
import org.bytedeco.ffmpeg.global.avcodec;
import org.bytedeco.ffmpeg.global.avutil;
import org.bytedeco.javacv.*;

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import static org.bytedeco.ffmpeg.global.avcodec.*;

/**
 * @author : 芊芊墨客
 * @version : 1.0
 * @date : 2023-05-20 12:18
 */
@Slf4j
public class VideoTranscoderController {

    @FXML
    public TextField input_file;

    @FXML
    public TextField output_file;

    @FXML
    public TextField output_file_name;

    @FXML
    public Button output_file_button;

    @FXML
    public Button input_file_button;

    @FXML
    public Button start_button;

    @FXML
    public ProgressBar progressbar;

    public SimpleObjectProperty<File> in_file = new SimpleObjectProperty<>();
    public SimpleObjectProperty<File> out_file = new SimpleObjectProperty<>();

    @FXML
    public MediaView mv;

    @FXML
    public AnchorPane mv_root;

    @FXML
    public void initialize() {

        // 绑定MediaView的宽度和高度到父容器的宽度和高度
        this.mv.setPreserveRatio(false);
        this.mv.fitHeightProperty().addListener(new ChangeListener<Number>() {
            @Override
            public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {
                System.out.println("fitHeightProperty:" + newValue.doubleValue());
            }
        });

        init_but(input_file_button);
        init_but(output_file_button);
        init_choose_dir_manager();
        init_choose_file_manager();

        this.start_button.setOnAction(event -> {
            this.mv.setFitWidth(mv_root.getWidth());
            this.mv.setFitHeight(mv_root.getHeight());
            if (input_file.getText().length() == 0){
                AlertUtils.alert_warning("请选择转码文件!");
                return;
            }

            if (output_file.getText().length() == 0){
                AlertUtils.alert_warning("输出文件目录不能为空!");
                return;
            }

            if (output_file_name.getText().length() == 0){
                AlertUtils.alert_warning("输出文件名称不能为空!");
                return;
            }
            in_file.setValue(new File(input_file.getText()));

            String out_file_path = output_file.getText() + output_file_name.getText();

            File file = new File(out_file_path);
            if (!file.exists()){
                try {
                    boolean newFile = file.createNewFile();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            out_file.set(new File(out_file_path));
            //转码
            ExecutorService executor = Executors.newSingleThreadExecutor();
            executor.submit(new TranscodeTask());
        });
    }


    public void init_choose_dir_manager(){
        this.output_file_button.setOnAction(event -> {
            Stage stage = new Stage();
            DirectoryChooser dc = new DirectoryChooser();
            dc.setTitle("文件夹选择器");
            File file = dc.showDialog(stage);
            if (file != null){
                String path = file.getAbsolutePath();
                output_file.setText(path);
            }
        });
    }

    public void init_choose_file_manager(){

        this.input_file_button.setOnAction(event -> {
            Stage stage = new Stage();
            FileChooser fc = new FileChooser();
            fc.setTitle("单选文件");
            fc.getExtensionFilters().addAll(
                    new FileChooser.ExtensionFilter("视频类型", "*.avi", "*.mp4","*.flv")
            );

            File file = fc.showOpenDialog(stage);
            if (file == null) {
                return;
            }
            input_file.setText(file.getAbsolutePath());
        });

    }

    public void init_but(Button input_file_button){
        input_file_button.setText(null);
        ImageView iv = new ImageView(new Image(ImagePath.path(ImagePath.ImagePathType.IMAGE_FILE)));
        iv.setPreserveRatio(true);
        iv.setFitWidth(18);
        input_file_button.setGraphic(iv);
    }

    private  class TranscodeTask extends Task<Void> {

        @Override
        protected Void call() throws Exception {
            try {
                FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(in_file.get());
                grabber.start();

                FFmpegFrameRecorder recorder = new FFmpegFrameRecorder(out_file.get(), grabber.getImageWidth(), grabber.getImageHeight(), grabber.getAudioChannels());
                String extension = FilenameUtils.getExtension(out_file.get().getName());
                recorder.setFormat(extension);
                recorder.setVideoCodec(grabber.getVideoCodec());
                recorder.setVideoBitrate(grabber.getVideoBitrate());
                recorder.setAudioCodec(grabber.getAudioCodec());
                recorder.setAudioBitrate(grabber.getAudioCodec());
                recorder.setFrameRate(grabber.getFrameRate());

                if (extension.equals("mp4")){
                    recorder.setVideoCodec(AV_CODEC_ID_MPEG4);
                }
                if (extension.equals("avi")){
                    recorder.setVideoCodec(AV_CODEC_ID_HUFFYUV);
                }
                if (extension.equals("flv")){
                    recorder.setVideoCodec(AV_CODEC_ID_FLV1);
                }

                recorder.start();

                int totalFrames = grabber.getLengthInFrames();
                int currentFrame = 0;

                while (currentFrame < totalFrames) {
                    Frame frame = grabber.grab();
                    updateProgress(currentFrame, totalFrames);
                    recorder.record(frame);
                    // 处理视频帧
                    currentFrame++;
                }

                grabber.stop();
                grabber.release();
                recorder.stop();
                recorder.release();

            } catch (FrameGrabber.Exception | FrameRecorder.Exception e) {
                e.printStackTrace();
            }
            return null;
        }

        @Override
        protected void succeeded() {
            progressbar.setProgress(1);
            AlertUtils.alert_msg("转码完成!");
            try {
                Media media = new Media(out_file.get().toURI().toASCIIString());
                MediaPlayer mediaPlayer = new MediaPlayer(media);
                mediaPlayer.setAutoPlay(true);
                mediaPlayer.setOnEndOfMedia(mediaPlayer::dispose);
                mv.setMediaPlayer(mediaPlayer);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        @Override
        protected void failed() {
            getException().printStackTrace();
        }

        @Override
        public void updateProgress(long current, long total) {
            double progress = (double) current / total;
            Platform.runLater(() -> progressbar.setProgress(progress));
        }
    }

}